
/* Generated by Interface Builder */

#import "Clock.h"
#import <appkit/Application.h>
#import <appkit/NXImage.h>
#import <appkit/View.h>
#import <soundkit/Sound.h>
#import <sys/time.h>
#import <math.h>
#import <dpsclient/wraps.h>
#import <appkit/Font.h>
#import <string.h>

#define STANDARD 3
#define ANALOG 4
#define GRANITE 5
#define DIGITAL 1
#define DIAGNAL 2
#define NUMBERED 6
#define BLACK 7
#define FIRST DIGITAL
#define LAST BLACK
#define MAX (LAST - FIRST + 2)

#define WDIAG (64.0 * sqrt(2.0))


NXPoint zero = {0.0, 0.0};

NXRect rect;	// Sort of a do everything kind of Rectangle
NXRect inside = { 0.0,0.0,64,64};


@implementation Clock

- setUpIcon 
{
    int startover;
    NXSize size = { 64.0, 64.0 };

    [self lockFocus];
    [back composite:NX_COPY toPoint:&zero];

do {
    startover = 0;
    switch(ctype) {
	case DIGITAL:
	    PSsetgray(NX_BLACK);
	    tFont = [Font newFont:"Times-Roman"
			size:18 style:0
			matrix:NX_IDENTITYMATRIX];
	    dFont = [Font newFont:"Helvetica"
			size:8 style:0
			matrix:NX_IDENTITYMATRIX];
	    image = [image free];	// This doesn't need an image
	    break;

	case DIAGNAL:
	    PSsetgray(NX_BLACK);
	    tFont = [Font newFont:"Times-Roman" 
			size:30.0 style:0
			matrix:NX_IDENTITYMATRIX];
	    [self setSeconds:NO];
	    image = [image free];
	    break;
	default:
	    if (image) image = [image free];
#ifdef BAD
	    image = [NXImage findImageNamed:[self getSectionName:ctype]];
#else
	    image = [[NXImage alloc] initFromSection:[self getSectionName:ctype]];
	    [image setScalable:YES];
	    [image setSize:&size];
#endif

#ifdef BAD
	    if (image == nil)
#else
	    if (![image composite:NX_SOVER toPoint:&zero])
#endif
	    {
		ctype = FIRST;
		startover = YES;
	    }
	    break;
    }
} while (startover == YES);

    [self unlockFocus];
    return self;
}
- init
{
    [super initFrame:&inside];
    [self setOpaque:YES];
    back = [[NXImage alloc] initFromSection:"blank"];
    timer = DPSAddTimedEntry(1.0, doStep, self, NX_BASETHRESHOLD);
    return self;
}

- free
{
    [image free];
    [back free];
    DPSRemoveTimedEntry(timer);
    [snd free];
    [tFont free];
    [dFont free];
    return [super free];
}

- setType:(int)TYPE;
{
    ctype = TYPE;
    [self setUpIcon];
    return self;
}

- (int)getType
{
    return (ctype);
}

float centerstring(id theFont, char *theString, float width)
{
    return ((width / 2.0) - ([theFont getWidthOf:theString] / 2.0));
}

- (const char *)getSectionName:(int)TYPE
{
    static char tmp[10];

    switch(TYPE) {
	case STANDARD:
	    return ("standard.tiff");
	    break;
	case ANALOG:
	    return ("analog.tiff");
	    break;
	case GRANITE:
	    return ("granite.tiff");
	    break;
	case DIGITAL:
	    return ("digital.tiff");
	    break;
	case DIAGNAL:
	    return ("diagnal.tiff");
	    break;
	case NUMBERED:
	    return ("analognumber.tiff");
	    break;
	case BLACK:
	    return ( "black.tiff");
	    break;
    }
    sprintf(tmp,"%d.tiff",TYPE - MAX + 1);
    return (tmp);    // I don't know what it so return it

}

void doStep(DPSTimedEntry teNum, double now, void *userData)
{
    [(id)userData display];
}

-drawSelf:(const NXRect *)rectangle :(int)rectCount
{

#define HOUR 15.0
#define MIN  22.0
#define SEC  24.0

    struct tm *curTime; 
    long theTime;
    int min, hour, sec, yy, dd, mm, day;
    float secang, minang, hourang;
    char *month[12] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
    char *Day[7] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
    char tmp[80], ap[3];

    // find the current time
    time(&theTime); curTime = localtime(&theTime);

    // set the variables equal to the current time
    sec = curTime->tm_sec; hour = curTime->tm_hour; min = curTime->tm_min;
    yy = curTime->tm_year; dd = curTime->tm_mday; mm = curTime->tm_mon;
    day = curTime->tm_wday;

    if (min == 0 && sec == 0 && Cflag)
	[snd play]; 

    [back composite:NX_COPY toPoint:&zero];
    if (image) [image composite:NX_SOVER toPoint:&zero];
    switch(ctype) {
	case STANDARD:
	    if (Mflag)
		if (Sflag) sprintf(tmp,"%02d:%02d:%02d",hour,min,sec);
		else sprintf(tmp,"%02d:%02d",hour,min);
	    else {
		if (hour<12) {
		    sprintf(ap,"am");
		    if (hour == 0) hour = 12;
		} else {
		    sprintf(ap,"pm");
		    if (hour > 12) hour -= 12;
		}
		sprintf(tmp,"%d:%02d %s",hour,min,ap);
	    }
	    tFont = [Font newFont:"Times-Italic"
			size:14 style:0
			matrix:NX_IDENTITYMATRIX];
	    [tFont set];	// Need to get the current context
	    PSsetgray(NX_WHITE);
	    PSmoveto(centerstring(tFont,tmp,64.0),47);
	    PSshow(tmp);
	    PSsetgray(NX_BLACK);
	    dFont = [Font newFont:"Helvetica"
		size:8 style:0
		matrix:NX_IDENTITYMATRIX];
	    [dFont set];
	    PSmoveto(centerstring(dFont,Day[day],64.0),34.0);
	    PSshow(Day[day]);
	    dFont = [Font newFont:"Times-Roman"
		size:24 style:0
		matrix:NX_IDENTITYMATRIX];
	    [dFont set];
	    sprintf(tmp,"%d",dd);
	    PSmoveto(centerstring(dFont,tmp,64.0),17);
	    PSshow(tmp);
	    dFont = [Font newFont:"Helvetica-Oblique"
		size:9 style:0
		matrix:NX_IDENTITYMATRIX];
	    [dFont set];
	    PSmoveto(centerstring(dFont,month[mm],64.0),10);
	    PSshow(month[mm]);

	    break;
	case DIGITAL:
	    if (Mflag)
		if (Sflag) sprintf(tmp,"%d:%02d:%02d",hour,min,sec);
		else sprintf(tmp,"%d:%02d",hour,min);
	    else {
		if (hour>12) hour = hour - 12;
		if (hour==0) hour = 12;			// Better way?
		if (Sflag) sprintf(tmp,"%d:%02d:%02d",hour,min,sec);
		else sprintf(tmp,"%d:%02d",hour,min);
	    }
	    [tFont set];
	    PSmoveto(centerstring(tFont,tmp,64.0),26.0);
	    PSshow(tmp);
	    sprintf(tmp,"%s %s %d",Day[day],month[mm],dd);
	    [dFont set];
	    PSmoveto(centerstring(dFont,tmp,64.0),19.0);
	    PSshow(tmp);
	    break;
	case DIAGNAL:
	    if (!Mflag) {
		if (hour>12) hour = hour - 12;
		if (hour==0) hour = 12;			// Better way?
	    }
	    sprintf(tmp,"%d:%02d",hour,min);
	    [tFont set];
	    PSrotate(45.0);
	    PSmoveto(centerstring(tFont,tmp,(float) WDIAG), -8.7);
	    PSshow(tmp);
	    break;
	default:    // This is where the analog clocks are handled
// Thanks to Scott Hess for the formulas.  I was too lazy to figure them out.
	    secang = (float)(sec*6*M_PI/180.0);
	    minang = (float)(min*6*M_PI/180.0);
	    hourang= ((hour)%12)*30*M_PI/180.0+minang/12;

	    PStranslate(32.0, 32.0);
	if (!Bflag) {    
	    if (Sflag) {
		PSsetlinewidth(0.0);
		if (ctype == GRANITE) PSsetgray(NX_WHITE);
		else if (ctype == BLACK) PSsetgray(NX_DKGRAY);
		else PSsetgray(NX_DKGRAY);
		PSmoveto(0.0,0.0);
		PSlineto(sin(secang)*SEC, cos(secang)*SEC);
		PSstroke();	// All of these strokes are needed since each of the lines is different
	    }

	    // Draw the minute hand
	    if (ctype == BLACK) PSsetgray(NX_LTGRAY);
	    else PSsetgray(NX_BLACK);
	    PSsetlinewidth(0.0);
	    PSmoveto((float)sin( minang)*MIN, (float)cos( minang)*MIN);
	    PSlineto(0.0, 0.0);
	    PSstroke();

	    // Draw the hour hand
	    PSsetlinewidth(1.5);
	    PSmoveto(0.0, 0.0);
	    PSlineto(sin(hourang)*HOUR,cos(hourang)*HOUR);
	} else {
	    /* More code from Scott Hess' Clocks program  */
	    PSsetlinewidth(0.0);
	    if (ctype == BLACK) PSsetgray(NX_LTGRAY); 
	    else PSsetgray(NX_BLACK);
	    PSmoveto(sin (minang)*MIN, cos(minang)*MIN);
	    if (Sflag)
		PScurveto(0,0,0,0,sin(secang)*SEC,cos(secang)*SEC);
	    PScurveto( 0,0,0,0,sin(hourang)*HOUR,cos(hourang)*HOUR);
	    PScurveto( 0,0,0,0,sin(minang)*MIN,cos(minang)*MIN);
	}
	PSstroke();
	PStranslate(-32.0, -32.0);
	    
	break;
    }
    return self;
}

- setMilitary:(BOOL)flag
{
    Mflag = flag;
    return self;
}

- (BOOL)getMilitary
{
    return Mflag;
}

- setSeconds:(BOOL)flag
{
    float timeOut;

    // Must always set the seconds even if you want them off.  This is where the timer is done
    Sflag = flag;
    if (Sflag)
	timeOut = 1.0;
    else
	timeOut = 60.0;

    if (timer != NULL) DPSRemoveTimedEntry(timer);  // I don't know what a bunch of these buggers will do
    timer = DPSAddTimedEntry(timeOut,doStep,self,NX_BASETHRESHOLD);
	
    return self;
}

- (BOOL)getSeconds
{
    return Sflag;
}

- setChime:(BOOL)flag
{
    Cflag = flag;
    return self;
}

- (BOOL)getChime;
{
    return Cflag;
}

- setBezier:(BOOL)flag
{
    Bflag = flag;
    return self;
}

- (BOOL)getBezier;
{
    return Bflag;
}

- setChimeFile:(char *)file;
{
    snd = [Sound removeSoundForName:"chime"];
    snd = [Sound addName:"chime" fromSoundfile:file];
    return self;
}

@end
